using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using GarageGames.Torque.T2D;
using GarageGames.Torque.Core;
using GarageGames.Torque.Materials;
using Xyne.Templates;
using GarageGames.Torque.GUI;
using Microsoft.Xna.Framework.Graphics;
using Xyne.Objects;
using Xyne.Templates.PuzzlePieceTemplate;
using Xyne.Utilities;
using Xyne.Objects.Common;
using Xyne.Actions;
using Xyne.CardManagement;
using System.IO;
using System.Xml.Serialization;
using Xyne.Events;
using Xyne.Templates.Card;
using Xyne.Templates.PuzzleGlowTemplate;

namespace Xyne.Regions
{
    public class HandRegionImpl : HandRegion
    {
        #region Private Vars
        private static Random random = new Random(DateTime.Now.Millisecond);
        private float cardHeight;
        private float cardWidth;
        private Vector2 cardOffset;
        private Vector2 patternOffset;
        private Vector2 patternSize;
        private Vector2 originCardOffset;
        private Vector2 buttonOffset;
        private Vector2 buttonSize;
        //private GUITextStyle cardTextStyle;

        private CardData[] cards;
        private List<int> dirtyCardIndices;

        private Deck deck;
        private Deck discard;

        private List<T2DStaticSprite>[] cardImages;

        private XyneText[] texts;

        int currentCardPressed;
        
        #endregion

        public HandRegionImpl(Rectangle Bounds, PuzzleRegion puzzle) : base(Bounds, puzzle)
        {
        }

        public override void Init(QueueRegion inQueue)
        {
            base.Init(inQueue);

            EventManager.Instance.Callbacks.Add(new EventManager.EventReceivedDelegate(EventReceived));

            cards = new CardData[4];
            dirtyCardIndices = new List<int>();
            currentCardPressed = -1;

            cardImages = new List<T2DStaticSprite>[4];
            for (int i = 0; i < 4; i++)
            {
                cardImages[i] = new List<T2DStaticSprite>();
            }

            GenerateDeck();

            #region InitBackground
            T2DSceneObject regionBackground = new T2DSceneObject();
            T2DStaticSprite background = new T2DStaticSprite();
            background.Size = new Vector2(Bounds.Width, Bounds.Height);
            background.Position = new Vector2(Bounds.Left + (Bounds.Width / 2), Bounds.Top + (Bounds.Height / 2));
            background.Layer = Game.BackgroundLayer;
            SimpleMaterial material = new SimpleMaterial();
            material.TextureFilename = @"data\images\handregion.PNG";
            background.Material = material;
            TorqueObjectDatabase.Instance.Register(background);
            #endregion

            #region DetermineSizes
            cardWidth = Bounds.Width;
            cardHeight = 100 * (cardWidth / 200);
            cardOffset = new Vector2(0, cardHeight + (Bounds.Height - (cardHeight * 4)) / 3);
            originCardOffset = new Vector2(Bounds.X + cardWidth / 2, Bounds.Y + cardHeight / 2);
            buttonOffset = new Vector2(12, cardHeight - 45);
            buttonSize = new Vector2(cardHeight * .3f, cardHeight * .3f);

            #region PatternBounds
            //patternOffset = new Vector2(0, -(cardHeight/2)+15);
            patternOffset = new Vector2(cardWidth *3/4-10, cardHeight/2);
            patternSize = new Vector2(cardWidth / 2 - 10, cardHeight - 30);
            #endregion
            #endregion

            InitCard(0);
            InitCard(1);
            InitCard(2);
            InitCard(3);

            texts = new XyneText[4];
            Resource<SpriteFont> tempFont = ResourceManager.Instance.LoadFont("Arial12");
            for (int k = 0; k < 4; k++)
            {
                XyneText tempText = new XyneText();
                tempText.Position = new Vector2(20,20);
                tempText.Font = tempFont;
                tempText.Text = string.Empty;
                tempText.Color = Color.White;
              //  Game.Instance.GameTexts.Add(tempText);
                texts[k] = tempText;
            }

            DrawCard(0);
            DrawCard(1);
            DrawCard(2);
            DrawCard(3);
        }

        private void EventReceived(Event e)
        {
            if (e is PatternSelectedEvent)
            {
                PatternSelectedEvent patternSelectedEvent = e as PatternSelectedEvent;
                T2DStaticSprite cardBackground = (T2DStaticSprite)TorqueObjectDatabase.Instance.FindObject("Card" + currentCardPressed.ToString() + "Background");
                if (cardBackground != null && cardBackground is Card)
                {
                    Card card = (Card)cardBackground;
                    card.SetCrackedBackground(patternSelectedEvent.NumSelected);

                    T2DStaticSprite sprite = PuzzleGlow.GetNewPuzzleGlow();
                    sprite.WarpToPosition(card.Icons[patternSelectedEvent.NumSelected-1].Position, 0);
                    TorqueObjectDatabase.Instance.Register(sprite);

                    PuzzlePulse pulse = (PuzzlePulse)PuzzlePulse.Template.Clone();
                    pulse.Visible = true;
                    pulse.WarpToPosition(card.Icons[patternSelectedEvent.NumSelected-1].Position, 0);
                    TorqueObjectDatabase.Instance.Register(pulse);

                    dirtyCardIndices.Add(currentCardPressed);
                }
            }
        }

        #region Card methods
        private void InitCard(int cardIndex)
        {
            Card card = (Card)Card.Template.Clone();
            card.Size = new Vector2(cardWidth, cardHeight);
            card.Position = GetCardPosition(cardIndex);
            card.Name = GetCardObjectName(cardIndex);
            TorqueObjectDatabase.Instance.Register(card);
        }

        public override void Start()
        {

        }

        private string GetCardObjectName(int cardIndex)
        {
            return "Card" + cardIndex.ToString() + "Background";
        }

        private Vector2 GetCardPosition(int cardIndex)
        {
            return originCardOffset + cardOffset * cardIndex;
        }

        public override void RefreshCards()
        {
            foreach (int cardIndex in dirtyCardIndices)
            {
                RefreshCard(cardIndex);
            }
            dirtyCardIndices.Clear();
            return;
        }

        private void RefreshCard(int cardIndex)
        {
            Vector2 cardPosition = GetCardPosition(cardIndex);

            RenderCardPattern(cardIndex);

            return;
        }

        private void RenderCardPattern(int cardIndex)
        {
            cardImages[cardIndex].Clear();
            PatternValue[,] pattern = cards[cardIndex].Pattern;
            Vector2 puzzlePieceSize = new Vector2(10, 10);
            if (pattern.Length > 0)
            {
                if (patternSize.X / pattern.GetLength(0) < patternSize.Y / pattern.GetLength(1))
                {
                    puzzlePieceSize = new Vector2(patternSize.X / pattern.GetLength(0), patternSize.X / pattern.GetLength(0));
                }
                else
                {
                    puzzlePieceSize = new Vector2(patternSize.Y / pattern.GetLength(1), patternSize.Y / pattern.GetLength(1));
                }
            }

            Vector2 puzzlePieceOrigin = patternOffset - new Vector2(puzzlePieceSize.X * pattern.GetLength(0) / 2, puzzlePieceSize.Y * pattern.GetLength(1) / 2);
            T2DStaticSprite cardBackground = (T2DStaticSprite)TorqueObjectDatabase.Instance.FindObject("Card" + cardIndex.ToString() + "Background");
            if (cardBackground is Card)
            {
                Card card = (Card)cardBackground;
                Vector2 oldSize = card.Size;
                card.Size = Card.DefaultSize;

                Texture2D tempBackgroundTexture = card.BackgroundTexture;

                for (int patternXIndex = 0; patternXIndex < pattern.GetLength(0); patternXIndex++)
                {
                    for (int patternYIndex = 0; patternYIndex < pattern.GetLength(1); patternYIndex++)
                    {
                        PatternValue tempColor = pattern[patternXIndex, patternYIndex];
                        if (tempColor.Value != PatternValueEnum.None && tempColor.Value != PatternValueEnum.Unknown)
                        {
                            PuzzlePieceColorEnum color = PuzzlePieceColorEnum.None;
                            switch (tempColor.Value)
                            {
                                case PatternValueEnum.Red: color = PuzzlePieceColorEnum.Red; break;
                                case PatternValueEnum.Blue: color = PuzzlePieceColorEnum.Blue; break;
                                case PatternValueEnum.Green: color = PuzzlePieceColorEnum.Green; break;
                                case PatternValueEnum.Yellow: color = PuzzlePieceColorEnum.Yellow; break;
                                case PatternValueEnum.White: color = PuzzlePieceColorEnum.White; break;
                                case PatternValueEnum.Black: color = PuzzlePieceColorEnum.Black; break;
                            }

                            if (color != PuzzlePieceColorEnum.None)
                            {
                                tempBackgroundTexture = MaterialHelper.CombineTextures(tempBackgroundTexture, PuzzlePieceMaterialManager.Instance.GetPuzzlePieceTexture(color), cardBackground.Size, puzzlePieceOrigin + new Vector2(puzzlePieceSize.X * patternXIndex, puzzlePieceSize.Y * patternYIndex), puzzlePieceSize);
                            }
                        }
                    }
                }
                if (cardBackground.Material == null)
                {
                    cardBackground.Material = new RenderMaterial();
                }

                //((XyneText)texts[cardIndex]).Text = cards[cardIndex].Name;
                //tempBackgroundTexture = MaterialHelper.DrawTextOnTexture(tempBackgroundTexture, texts[cardIndex], cardBackground.Size);
                tempBackgroundTexture = MaterialHelper.CombineTextures(tempBackgroundTexture, MaterialHelper.Instance.GetButtonTexture((ButtonEnum)cardIndex), cardBackground.Size, buttonOffset, buttonSize);
                (cardBackground.Material as SimpleMaterial).SetTexture(tempBackgroundTexture);

                card.Size = oldSize;
            }
        }

        public override bool CardPressed(int cardIndex)
        {
            if (PuzzleRegion.LoadPattern(cards[cardIndex].Pattern, new PuzzleRegion.UnloadPatternDelegate(CardUnloaded)))
            {
                Card cardBackground = (Card)TorqueObjectDatabase.Instance.FindObject("Card" + cardIndex.ToString() + "Background");
                ResizeCard(cardIndex, 1.2f);
                currentCardPressed = cardIndex;
                
                return true;
            }
            else
            {
                PuzzleRegion.UnloadPattern();
                return false;
            }
        }

        public override void CardDepressed(int cardIndex)
        {
            CardUnloaded(PuzzleRegion.UnloadPattern());
        }

        private void CardUnloaded(int numGems)
        {
            ResizeCard(currentCardPressed, 1 / 1.2f);
            if (numGems > 0)
            {
                if (Game.Network != null)
                {
                    foreach (Action action in cards[currentCardPressed].Actions)
                    {
                        if (action.MinLevel <= numGems && action.MaxLevel >= numGems)
                        {
                            action.Level = numGems;

                            Game.Network.HandleAction(action);
                        }
                    }
                }
                DrawCard(currentCardPressed);
            }
            currentCardPressed = -1;
        }

        private void ResizeCard(int cardIndex, float change)
        {
            Card cardBackground = (Card)TorqueObjectDatabase.Instance.FindObject("Card" + cardIndex.ToString() + "Background");
            if (cardBackground != null)
            {
                cardBackground.Size = cardBackground.Size * change;
                foreach (CardIcon cardIcon in cardBackground.Icons)
                {
                    cardIcon.Size = cardIcon.Size * change;
                }
            }
        }

        private void ClearPattern(int cardIndex)
        {
            foreach (T2DStaticSprite image in cardImages[cardIndex])
            {
                TorqueObjectDatabase.Instance.Unregister(image);
            }

            cardImages[cardIndex].Clear();
        }
        #endregion

        #region Deck Methods
        private void GenerateDeck()
        {
            // Temporarily load a deck from the standard card pack
     //       deck = new Deck();
            deck = UserSaveDataManager.Instance.UserSaveData.UserDeck;
            deck.InitCardActions();

            deck = deck.CreateShuffledDeck();

            discard = new Deck();
    /*        

            CardPack pack = new CardPack();
            XmlSerializer serializer = new XmlSerializer(pack.GetType());
            FileStream stream = new FileStream(@"Packs\Standard.xml", FileMode.Open, FileAccess.Read);
            pack = serializer.Deserialize(stream) as CardPack;
            stream.Close();

            // Generate a couple cards from the pack
            Deck tempDeck = new Deck();
            foreach (CardData card in pack.Cards)
            {
                // Copy it a few times for testing
                for (int c = 0; c < 5; c++)
                {
                    CardData newCard = new CardData(card);
                    for (int i = 0; i < newCard.Actions.Count; i++)
                    {
                        newCard.Actions[i].InitializeActualObjects();

                        if (newCard.Actions[i].OnCollision != null)
                            newCard.Actions[i].OnCollision.Action.InitializeActualObjects();
                    }
                    tempDeck.GetCards().Enqueue(newCard);
                }
            }
            deck = tempDeck.CreateShuffledDeck();
     * */

        }

        private void DrawCard(int cardIndex)
        {
            Discard(cardIndex);
            if (deck.GetCards().Count == 0)
            {
                deck = discard.CreateShuffledDeck();
            }
            CardData card = deck.GetCards().Dequeue();
            cards[cardIndex] = card;
            discard.GetCards().Enqueue(card);

            Card cardBackground = (Card)TorqueObjectDatabase.Instance.FindObject(GetCardObjectName(cardIndex));
            if (cardBackground != null && cardBackground is Card)
            {
                cardBackground.ResetBackground();
            }
            ((SimpleMaterial)cardBackground.Icons[0].Material).SetTexture(MaterialHelper.Instance.GetIconTexture(card.Icon, 1));

            ((SimpleMaterial)cardBackground.Icons[1].Material).SetTexture(MaterialHelper.Instance.GetIconTexture(card.Icon, 2));

            ((SimpleMaterial)cardBackground.Icons[2].Material).SetTexture(MaterialHelper.Instance.GetIconTexture(card.Icon, 3));

            dirtyCardIndices.Add(cardIndex);
        }

        private void Discard(int cardIndex)
        {
            ClearPattern(cardIndex);
        }
        #endregion
    }
}
